package org.fixed.dubboconsumer.core.util;

import org.apache.commons.lang.StringUtils;
import org.fixed.dubboconsumer.entity.ResourceVO;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * 〈一句话功能简述>
 * ${DESCRIPTION}
 * Author:xuzhongwei
 * Date:2019/1/2
 */

public class JarUtils {

    protected static Method addURL = null;

    static {
        try {
            addURL = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
            addURL.setAccessible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过maven 的依赖来加载jar
     *
     * @param mavenContent
     * @param interfaceName
     * @return
     * @throws InvocationTargetException
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    public static Class mvnLoad(String mavenContent, String interfaceName) throws InvocationTargetException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, ParserConfigurationException, SAXException {
        String groupId = getXmlNode(mavenContent, "groupId");
        String artifactId = getXmlNode(mavenContent, "artifactId");
        String version = getXmlNode(mavenContent, "version");
        //maven 的配置还有如classifier等限制，但通常自己写的jar是没有的。只有这3种。
        return JarUtils.mvnLoad( groupId, artifactId, version, interfaceName);
    }

    /**
     * 从maven仓库读取jar
     *
     * @param groupId
     * @param artifactId
     * @param version
     */
    private static Class mvnLoad( String groupId, String artifactId, String version, String className) throws IllegalAccessException, InvocationTargetException, MalformedURLException, InstantiationException, ClassNotFoundException {
        File jar = MavenRepository.loadWithDependency(groupId, artifactId, version);
        return JarUtils.jarLoad(jar, className);
    }

    /**
     * 从指定路径读取
     *
     * @param jarPath
     * @param className
     */
    public static Class jarLoad(String jarPath, String className) throws MalformedURLException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        JarUtils.jarLoad(jarPath);
        return Class.forName(className);
    }

    public static Class jarLoad(File jar, String className) throws MalformedURLException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        JarUtils.jarLoad(jar);
        return Class.forName(className);
    }

    public static void jarLoad(File jar) throws MalformedURLException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        jarLoad(jar.toURI().toURL());
    }

    /**
     * 从指定路径读取
     *
     * @param jarPath
     */
    public static void jarLoad(String jarPath) throws MalformedURLException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        URL targetUrl = null;
        if (StringUtils.contains(jarPath, "http")) {
            targetUrl = new URL(jarPath);
        } else {
            File file = new File(jarPath);
            targetUrl = file.toURI().toURL();
        }
        jarLoad(targetUrl);
    }

    private static void jarLoad(URL targetUrl) throws InvocationTargetException, IllegalAccessException {
        URLClassLoader loader = (URLClassLoader) JarUtils.class.getClassLoader();
        boolean isLoader = false;
        for (URL url : loader.getURLs()) {
            if (url.equals(targetUrl)) {
                isLoader = true;
                break;
            }
        }
        if (!isLoader) {
            addURL.invoke(loader, new Object[]{targetUrl});
        }
    }

    private static String getXmlNode(String str, String name) {
        String temp = "<" + name + ">";
        int start = str.indexOf(temp) + temp.length();
        int end = str.indexOf("</" + name + ">");
        if (start < end) {
            return StringUtils.substring(str, start, end);
        }
        return null;
    }

    /**
     * 获取接口信息
     *
     * @param resourceVO
     * @return
     * @throws Exception
     */
    public static Class getInterfaceClass(ResourceVO resourceVO) throws Exception {
        Class clazz = null;
        switch (resourceVO.getResourceType()) {
            case "1":
                clazz = mvnExe(resourceVO);
                break;
            case "2":
                clazz = jarExe(resourceVO);
                break;
        }

        if (null == clazz) {
            throw new Exception("无法获取到接口信息");
        }
        return clazz;
    }

    public static Class mvnExe(ResourceVO resourceVO) throws Exception {
        return JarUtils.mvnLoad(resourceVO.getMavenContent(), resourceVO.getInterfaceName());
    }

    public static Class jarExe(ResourceVO resourceVO) throws Exception {
        String[] path = StringUtils.split(resourceVO.getJarPath(), ",");
        for (String jarPath : path) {
            JarUtils.jarLoad(jarPath);
        }
        return Class.forName(resourceVO.getInterfaceName());
    }


}
